/******************************************************************************
 * * call_api.c - API invoked by other modules other than call
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/
#include "call_global.h"

#if USE_LV_INTERPHONE_TEST == 0
/**
 * To get activeIndex from SimId and Index
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * return  UINT8: index of g_MMI_Call_Mng.Calls
 */
static UINT8 Call_Get_Param_Index(MMI_MODEM_SIM_ID SimId, INT32 Index)
{
    if (  (NULL != g_MMI_Call_Mng.Calls[0]) && (SimId == g_MMI_Call_Mng.Calls[0]->SimId)
       && (Index == g_MMI_Call_Mng.Calls[0]->Index))
    {
        return(0);
    }
    else if (  (NULL != g_MMI_Call_Mng.Calls[1]) && (SimId == g_MMI_Call_Mng.Calls[1]->SimId)
            && (Index == g_MMI_Call_Mng.Calls[1]->Index))
    {
        return(1);
    }
    else
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_WARNING, "*****error*****\n");
        return(UI_CALL_INVALID_PARAM_INDEX);
    }
}


/**
 *
 * This message is sent to the calling mobile station
 * to indicate that the call is originating. (after ATD <number>;)
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * return  void
 */
VOID Phone_Modem_Call_Response_Originating(MMI_MODEM_SIM_ID SimId, INT32 Index)
{
    if (NULL == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex])
    {           // call has been disconnect before originating, ignor this api
        return; // ignore
    }

    if(MMI_MODEM_CALL_STATE_DIALING == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State)
    {
        return;
    }

    // state: NULL -> DIALLING
    g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State = MMI_MODEM_CALL_STATE_DIALING;
    g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->Index = Index;
    Framework_Call_Calling_Or_Incoming_Ind(TRUE, FALSE);
    Call_Print_Call_Info(__FUNCTION__);
}

/**
 *
 * This message is sent to the calling mobile station
 * to indicate that the called user alerting has been initiated.
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * return  void
 */
VOID Phone_Modem_Call_Response_Alerting(MMI_MODEM_SIM_ID SimId, INT32 Index)
{
    if (NULL == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex])
    {           // call has been disconnect before alerting, ignor this api
        return; // ignore
    }

    if(MMI_MODEM_CALL_STATE_ALERTING == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State)
    {
        return;
    }

    g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State =
        MMI_MODEM_CALL_STATE_ALERTING;  // state: DIALLING -> ALERTING
    Call_Spk_Ctrl(FALSE);               // turn on the handset
    Nav_Back(ACT_ID_ANY);               // pop Alerting ui
    Display_Call_Main();                // Display_Call_Main
    Call_Print_Call_Info(__FUNCTION__);
}

/**
 *
 * This message is sent to the called mobile station
 * to indicate an incoming call (voice, data or fax). (RING)
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * return  void
 */
VOID Phone_Modem_Call_Response_Ring(MMI_MODEM_SIM_ID SimId, INT32 Index)
{
    UI_Call_Params_t *CallParams;

    if((NULL != g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex])
        && ((MMI_MODEM_CALL_STATE_INCOMING == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State)
        || (MMI_MODEM_CALL_STATE_DIALING == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State) //ringback
        || (MMI_MODEM_CALL_STATE_ALERTING == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State)))
    {
        return;
    }

    CallParams = (UI_Call_Params_t *)Hal_Mem_Alloc(sizeof(UI_Call_Params_t));
    Hal_Mem_Set(CallParams, 0, sizeof(UI_Call_Params_t));
    g_MMI_Call_Mng.ActiveIndex = Call_Get_Free_Line();             // get free line
    if (g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex] == NULL)
    {
        g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex] = CallParams;
        Call_Set_Line_On(g_MMI_Call_Mng.ActiveIndex);
    }
    else
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "error\n");
        // Assert();
        return;
    }

    CallParams->SimId      = SimId;
    CallParams->Index      = Index;
    CallParams->IsMT       = TRUE;
    CallParams->State      = MMI_MODEM_CALL_STATE_INCOMING;

    if(NULL != g_MMI_Call_Mng.DisplayTimer) {
        Hal_Timer_Stop(g_MMI_Call_Mng.DisplayTimer);
        Call_Display_Timeout(&g_MMI_Call_Mng.StatusAct);
    }

    Call_Print_Call_Info(__FUNCTION__);
}

/**
 * This message is sent to the calling/called mobile station
 * to indication that the call is connected.
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * return  void
 */
VOID Phone_Modem_Call_Response_Connect(MMI_MODEM_SIM_ID SimId, INT32 Index)
{
    UI_Call_Params_t *CallParams;
    UINT8            ParamIndex = Call_Get_Param_Index(SimId, Index);

    if (UI_CALL_INVALID_PARAM_INDEX == ParamIndex)
    {   // call has been disconnect before originating, ignor this api
        return;
    }

    CallParams = g_MMI_Call_Mng.Calls[ParamIndex];

    if (NULL == CallParams)
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "unexpected connect, ignore\n");
        return;
    }

    if(MMI_MODEM_CALL_STATE_ACTIVE == CallParams->State)
    {
        return;
    }

    if (MMI_MODEM_CALL_STATE_WAITING != CallParams->State)
    {
        if (MMI_MODEM_CALL_STATE_INCOMING == CallParams->State)
        {
            Call_Stop_Ring();   //do this for ATA from serial port
            Audio_Player_Audio_Stop();
            Call_Spk_Ctrl(FALSE);               // turn on the handset
        }

        g_MMI_Call_Mng.IsConnect = TRUE;
        Call_Duration_Start();
        Nav_Back(ACT_ID_ANY);               // pop calling UI
        Display_Call_Main();
    }
    else
    {
        g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_NULL;  // clear call process

        // set state of the other Call to holding
        if (UI_CALL_LINE_ALL == g_MMI_Call_Mng.CallsBitMap)
        {
            g_MMI_Call_Mng.Calls[(ParamIndex + 1) % 2]->State = MMI_MODEM_CALL_STATE_HOLDING;
        }
        else
        {
            UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "ERROR: call bitmap %d\n", g_MMI_Call_Mng.CallsBitMap);
        }
    }

    CallParams->Duration = 0;     // start tu record duration for call log
    CallParams->State    = MMI_MODEM_CALL_STATE_ACTIVE;
    Call_Print_Call_Info(__FUNCTION__);
} /* MMI_Modem_Call_Response_Connect */

/**
 * This message is sent to the calling/called mobile station
 * to indication that the call is disconnected.
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * return  void
 */
VOID Phone_Modem_Call_Response_Disconnect(MMI_MODEM_SIM_ID SimId, INT32 Index)
{
#if 0
    NV_Call_Log_Data_t *CallLogData;
    UINT8              ParamIndex = Call_Get_Param_Index(SimId, Index);
    UI_Call_Params_t   *CallParams;

    if (UI_CALL_INVALID_PARAM_INDEX == ParamIndex)
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "no connection currently\n");
        return;
    }

    CallParams = g_MMI_Call_Mng.Calls[ParamIndex];

    if (NULL == CallParams)
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "no connection currently\n");
        return;
    }

    // record call log
    CallLogData = (NV_Call_Log_Data_t *)Hal_Mem_Alloc(sizeof(NV_Call_Log_Data_t));
    Hal_Mem_Set(CallLogData, 0, sizeof(NV_Call_Log_Data_t));

    if (TRUE == CallParams->IsMT)
    {
        if (  (MMI_MODEM_CALL_STATE_WAITING == CallParams->State)
           || (MMI_MODEM_CALL_STATE_INCOMING == CallParams->State))
        {                                                      // in waiting state
            CallLogData->Type = CALL_LOG_TYPE_MISSED;
            g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_NULL; // clear call process
        }
        else
        {
            CallLogData->Type = CALL_LOG_TYPE_RECEIVED;
        }
    }
    else
    {
        CallLogData->Type = CALL_LOG_TYPE_DIALLED;
    }

    if (NULL != CallParams->Name)
    {
        Hal_Mem_Copy(CallLogData->Name, CallParams->Name, strlen(CallParams->Name));
    }

    Hal_Mem_Copy(CallLogData->Number, CallParams->Number, strlen(CallParams->Number));
    CallLogData->SimId     = CallParams->SimId;
    CallLogData->Duration  = CallParams->Duration;
    CallLogData->Timestamp = UI_Get_Timestamp_In_Second();
    CallLog_Call_Add_Log(CallLogData);

    Call_Set_Line_Off(ParamIndex); // clear line
    if (UI_CALL_LINE_NONE == g_MMI_Call_Mng.CallsBitMap)
    {                              // no line left, indicate no connection to Framework
        g_MMI_Call_Mng.IsConnect = FALSE;
        Display_Call_End();        // display call end interface
        Framework_Call_Calling_Or_Incoming_Ind(FALSE, FALSE);
        Call_Duration_Stop();      // stop duration timer and reset variable Duration.
    }
    else
    {
        g_MMI_Call_Mng.ActiveIndex = (ParamIndex + 1) % 2;                      // set other index active
    }

    // delete this call from g_Calls
    if (NULL != CallParams)
    {
        Call_Clear_Call_Paras(ParamIndex);
    }
    else
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "Call Response Disconnect should not received\n");
        return;
    }
#endif
    Call_Print_Call_Info(__FUNCTION__);
} /* MMI_Modem_Call_Response_Disconnect */

/**
 * Indicates a disconnect for Call Clearing or a Call Failed for an outgoing call. (NO CARRIER)
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * return  void
 */
VOID Phone_Modem_Call_Response_No_Carrier(MMI_MODEM_SIM_ID SimId, INT32 Index, UINT8 isNoCarrier)
{
    UINT8            ParamIndex = g_MMI_Call_Mng.ActiveIndex;//Call_Get_Param_Index(SimId, Index);
    UI_Call_Params_t *CallParams;
    If_Setting_Play_Tone_t *PlayToneReq;
    NV_Call_Log_Data_t *CallLogData;
    CALL_LOG_TYPE CallLogType = CALL_LOG_TYPE_NONE;

    if (UI_CALL_INVALID_PARAM_INDEX == ParamIndex)
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "no connection currently\n");
        return;
    }

    CallParams = g_MMI_Call_Mng.Calls[ParamIndex];

    if (NULL == CallParams)
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "Call Response No Carrier should not received\n");
        return;
    }

    printf("%s: state %d, IsMt %d, CallPross %d\n",
           __FUNCTION__, CallParams->State, CallParams->IsMT, g_MMI_Call_Mng.CallProcess);

    if(NULL != g_MMI_Call_Mng.DisplayTimer) {
        Hal_Timer_Stop(g_MMI_Call_Mng.DisplayTimer);
        Call_Display_Timeout(&g_MMI_Call_Mng.StatusAct);
    }

    // record call log
    if (TRUE == CallParams->IsMT)
    {
        if (  (MMI_MODEM_CALL_STATE_WAITING == CallParams->State)
              || (MMI_MODEM_CALL_STATE_INCOMING == CallParams->State))
        {                                                      // in waiting state
            if (UI_CALL_PROCESS_MT_AUTO_REJECT == g_MMI_Call_Mng.CallProcess)
            {
                Call_Clear_Call_Paras(ParamIndex);
                Call_Duration_Stop();      // stop duration timer and reset variable Duration.
                g_MMI_Call_Mng.IsConnect = FALSE;
                g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_NULL;  // clear call process
                if (FALSE == Framework_Get_Lcd_Status())
                {
                    Framework_Suspend();
                }
                return;
            }
            else if (UI_CALL_PROCESS_MT_REJECT == g_MMI_Call_Mng.CallProcess)
            {
                CallLogType = CALL_LOG_TYPE_RECEIVED;
            }
            else
            {
                CallLogType = CALL_LOG_TYPE_MISSED;
            }
        }
        else
        {
            CallLogType = CALL_LOG_TYPE_RECEIVED;
        }
    }
    else
    {
        CallLogType = CALL_LOG_TYPE_DIALLED;
    }
    CallLogData = (NV_Call_Log_Data_t *)Hal_Mem_Alloc(sizeof(NV_Call_Log_Data_t));
    Hal_Mem_Set(CallLogData, 0, sizeof(NV_Call_Log_Data_t));
    CallLogData->Type = CallLogType;
    if (NULL != CallParams->Name)
    {
        Hal_Mem_Copy(CallLogData->Name, CallParams->Name, strlen(CallParams->Name));
    }
    Hal_Mem_Copy(CallLogData->Number, CallParams->Number, strlen(CallParams->Number));
    CallLogData->SimId     = CallParams->SimId;
    CallLogData->Duration  = CallParams->Duration;
    CallLogData->Timestamp = UI_Get_Timestamp_In_Second();
    CallLog_Call_Add_Log(CallLogData);

    PlayToneReq           = (If_Setting_Play_Tone_t *)Hal_Mem_Alloc(sizeof(If_Setting_Play_Tone_t));
    PlayToneReq->PlayCtrl = IF_SETTING_PLAY_TONS_STOP;
    Setting_Play_Tone_Req(PlayToneReq);

    Hal_Set_Voice_Call_Status(VOICE_CALL_END);
    //display ui
    ACTIVITY_ID TopAct = Nav_Get_Top();
    if ((ACT_ID_CALL_EMERGENCY_CALLING <= TopAct)
        && (ACT_ID_CALL_DTMF_INPUT >= TopAct))
    {
        Display_Call_End();
    }
    else
    {
        g_MMI_Call_Mng.FromAct = ACT_ID_ANY;

        ACTIVITY_ID ActId;
        INT8 Idx = Nav_Get_Index(ACT_ID_CALL_MAIN);

        if(Idx >= 0)
        {
            ActId = Nav_Get_Prev(ACT_ID_CALL_MAIN);

            if(ACT_ID_MAX != ActId)
            {
                Nav_Forward(ACT_ID_CALL_MAIN, ActId, NULL, NULL);            //remove call main from stack
            }
        }
    }

    Call_Spk_Ctrl(TRUE);       // turn on the speaker
    Audio_Player_Audio_Contine();
    //disconnect BT audio path
    Hal_Disconnect_BT_Audio_Path();
    Call_Clear_Call_Paras(ParamIndex);
    Call_Duration_Stop();      // stop duration timer and reset variable Duration.
    g_MMI_Call_Mng.IsConnect = FALSE;

    if (CALL_LOG_TYPE_MISSED == CallLogType)
    {
        Framework_Call_Calling_Or_Incoming_Ind(FALSE, TRUE);
    }
    else
    {
        Framework_Call_Calling_Or_Incoming_Ind(FALSE, FALSE);
    }

    g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_NULL;  // clear call process

    Call_Print_Call_Info(__FUNCTION__);
}

/**
 * Indicates the calling line identity of the calling party after every RING/+CRING. (+CLIP:)
 * +CLIP: <number>,<type>
 *
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * param Clip:  MMI_MODEM_CALL_RESPONSE_CLIP *
 * return  void
 */
VOID Phone_Modem_Call_Response_Clip(MMI_MODEM_SIM_ID SimId, INT32 Index,
                                    MMI_Modem_Call_Response_Clip_t *Clip)
{
    UI_Call_Params_t           *CallParams = g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex];
    If_Contacts_Contact_Para_t ContactPara;
    If_Setting_Play_Tone_t     *PlayToneReq;
    INT8 *NewNumber = NULL;
    UINT8 NumLen = 0;
    UINT8 NewNumLen = 0;
    const UINT8 MaxLen = 11;

    if((NULL != CallParams)
        && (MMI_MODEM_CALL_STATE_INCOMING == CallParams->State)
        && (NULL != CallParams->Number))
    {
        Hal_Mem_Free(Clip->number);
        Hal_Mem_Free(Clip);
        return;
    }

    if(NULL != g_MMI_Call_Mng.DisplayTimer) {
        Hal_Timer_Stop(g_MMI_Call_Mng.DisplayTimer);
        Call_Display_Timeout(&g_MMI_Call_Mng.StatusAct);
    }

    //set CallParams
    if(NULL == CallParams) {
        CallParams = (UI_Call_Params_t *)Hal_Mem_Alloc(sizeof(UI_Call_Params_t));
        Hal_Mem_Set(CallParams, 0, sizeof(UI_Call_Params_t));
        g_MMI_Call_Mng.ActiveIndex = Call_Get_Free_Line();             // get free line
        if (g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex] == NULL)
        {
            g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex] = CallParams;
            Call_Set_Line_On(g_MMI_Call_Mng.ActiveIndex);
        }
        else
        {
            UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "error\n");
            // Assert();
        }
    }

    CallParams->SimId      = SimId;
    CallParams->Index      = Index;
    CallParams->IsMT       = TRUE;
    CallParams->State      = MMI_MODEM_CALL_STATE_INCOMING;

    //remove prefix 86
    NewNumLen = NV_CONTACTS_MAX_NUMBER_LEN * sizeof(INT8);
    NewNumber = (INT8 *)Hal_Mem_Alloc(NewNumLen);
    Hal_Mem_Set(NewNumber, 0 , NewNumLen);

    NumLen = strlen(Clip->number);
    if(NumLen >= 13)
    {
        strncpy(NewNumber, Clip->number + NumLen - MaxLen, MaxLen);
    }
    else
    {
        strncpy(NewNumber, Clip->number, NumLen);
    }
    printf("%s: NewNumber=%s\n", __FUNCTION__, NewNumber);

    Contacts_Get_Contact_Para_Req(NewNumber, &ContactPara);
    // set call number
    CallParams->Number = (INT8 *)Hal_Mem_Alloc(strlen(NewNumber) + 1);
    Hal_Mem_Set(CallParams->Number, 0, strlen(NewNumber) + 1);
    if (NULL != CallParams->Number)
    {
        Hal_Mem_Copy(CallParams->Number, NewNumber, strlen(NewNumber));
        Hal_Mem_Free(NewNumber);
        Hal_Mem_Free(Clip->number);
        Hal_Mem_Free(Clip);
    }
    else
    {
        // Assert();
    }

    // set call name
    if (0 != strlen(ContactPara.Name))
    {
        CallParams->Name = (INT8 *)Hal_Mem_Alloc(strlen(ContactPara.Name) + 1);
        Hal_Mem_Set(CallParams->Name, 0, strlen(ContactPara.Name) + 1);
        Hal_Mem_Copy(CallParams->Name, ContactPara.Name, strlen(ContactPara.Name));
    }
    else
    {
        CallParams->Name = NULL;
    }

    if (TRUE == ContactPara.NumScrnFlg)
    {   // screened number, reject the incoming call
        MMI_Modem_Call_Request_Udub(CallParams->SimId);
        g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_MT_AUTO_REJECT;
        return;
    }

    if (IF_CONTACTS_NO_TONE != ContactPara.ToneIndex)
    {
        // play tone
        PlayToneReq =
            (If_Setting_Play_Tone_t *)Hal_Mem_Alloc(sizeof(If_Setting_Play_Tone_t));
        PlayToneReq->SimId    = CallParams->SimId;
        PlayToneReq->ToneType = IF_SETTING_TONS_TYPE_CALL;
        if (IF_CONTACTS_DEFAULT_TONE == ContactPara.ToneIndex)
        {
            PlayToneReq->SpecToneIndex = IF_SETTING_INVALID_TONE;
        }
        else
        {
            PlayToneReq->SpecToneIndex = ContactPara.ToneIndex;
        }
        PlayToneReq->PlayCtrl = IF_SETTING_PLAY_TONS_START;
        Setting_Play_Tone_Req(PlayToneReq);
    }

    g_MMI_Call_Mng.FromAct = Nav_Get_Top();              // save ACT UI from
    printf("%s: FromAct=%d\n", __FUNCTION__, g_MMI_Call_Mng.FromAct);

    Display_Call_Incoming();
    Framework_Update_Status(TRUE);
    Framework_Set_Lcd_Status(TRUE);
    Framework_Call_Calling_Or_Incoming_Ind(TRUE, FALSE);
    Call_Print_Call_Info(__FUNCTION__);
} /* MMI_Modem_Call_Response_Clip */
#endif

/**
 * Indicates Call Waiting (CW) information (when enabled) for an incoming call. (+CCWA:)
 * +CCWA: <number>,<type>,<class>,[<alpha>][,<CLI validity>[,<subaddr>,<satype>[,<priority>]]]
 *
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * param Ccwa:  MMI_MODEM_CALL_RESPONSE_CCWA *
 * return  void
 */
VOID Phone_Modem_Call_Response_Ccwa(MMI_MODEM_SIM_ID SimId, INT32 Index,
                                  MMI_Modem_Call_Response_Ccwa_t *Ccwa)
{
    UINT8                      ParamIndex;
    UI_Call_Params_t           *CallParams;
    If_Contacts_Contact_Para_t ContactPara;

    if (UI_CALL_LINE_MAX == Call_Get_Free_Line())
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "not support more than 2 connects currently\n");
        return;
    }

    ParamIndex  = Call_Get_Free_Line();   // Get free Index
    Contacts_Get_Contact_Para_Req(Ccwa->number, &ContactPara);
    if (0 < strlen(ContactPara.Name))
    {
        Call_Enter_Call_Paras(ParamIndex, ContactPara.Name, Ccwa->number);
    }
    else
    {
        Call_Enter_Call_Paras(ParamIndex, NULL, Ccwa->number);
    }

    CallParams        = g_MMI_Call_Mng.Calls[ParamIndex];
    CallParams->SimId = SimId;
    CallParams->Index = Index;
    CallParams->IsMT  = TRUE;
    CallParams->State = MMI_MODEM_CALL_STATE_WAITING;

    if (TRUE == ContactPara.NumScrnFlg)
    {
        g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_MT_REJECT;
        MMI_Modem_Call_Request_Udub(SimId);
    }

    Hal_Mem_Free(Ccwa);
    Call_Print_Call_Info(__FUNCTION__);
} /* MMI_Modem_Call_Response_Ccwa */

/**
 * Indicats the call state is changed
 *
 * param State:  MMI_MODEM_CALL_RESPONSE_STATE_CHANGE *
 * return  void
 */
VOID Phone_Modem_Call_Response_State_Change(MMI_Modem_Call_Response_State_Change_t *State)
{
#if 0
    UINT8            i;
    UINT8            ParamIndex;
    UI_Call_Params_t *CallParams;

    Call_Print_Call_Info(__FUNCTION__);
    for (i = 0; i < State->count; i++)
    {
        ParamIndex = Call_Get_Param_Index(State->calls[i].simId, State->calls[i].index);
        if (UI_CALL_INVALID_PARAM_INDEX == ParamIndex)
        {
            UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "no connection currently\n");
            continue;
        }
        else
        {
            CallParams = g_MMI_Call_Mng.Calls[ParamIndex];
        }

        if (NULL == CallParams)
        {
            continue;
        }

        switch (g_MMI_Call_Mng.CallProcess)
        {
        case UI_CALL_PROCESS_HOLD:
        {
            if (  (MMI_MODEM_CALL_STATE_ACTIVE == CallParams->State)
               && (MMI_MODEM_CALL_STATE_HOLDING == State->calls[i].state))
            {
                Display_Call_Hold();
                CallParams->State          = MMI_MODEM_CALL_STATE_HOLDING;
                g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_NULL;
            }
            else
            {
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "Call state wrong %d", CallParams->State);
            }

            break;
        }

        case UI_CALL_PROCESS_UNHOLD:
        {
            if (  (MMI_MODEM_CALL_STATE_HOLDING == CallParams->State)
               && (MMI_MODEM_CALL_STATE_ACTIVE == State->calls[i].state))
            {
                Display_Call_Unhold();
                CallParams->State          = MMI_MODEM_CALL_STATE_ACTIVE;
                g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_NULL;
            }
            else
            {
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "Call state wrong %d", CallParams->State);
            }

            break;
        }

        case UI_CALL_PROCESS_SWAP:
        {
            if (  (  (MMI_MODEM_CALL_STATE_WAITING == CallParams->State)
                  || (MMI_MODEM_CALL_STATE_HOLDING == CallParams->State))
               && (MMI_MODEM_CALL_STATE_ACTIVE == State->calls[i].state))
            {
                CallParams->State          = MMI_MODEM_CALL_STATE_ACTIVE;
                g_MMI_Call_Mng.ActiveIndex = ParamIndex;
            }
            else if (  (MMI_MODEM_CALL_STATE_ACTIVE == CallParams->State)
                    && (  (MMI_MODEM_CALL_STATE_WAITING == CallParams->State)
                       || (MMI_MODEM_CALL_STATE_HOLDING == State->calls[i].state)))
            {
                CallParams->State = MMI_MODEM_CALL_STATE_HOLDING;
            }

            if (1 == i)
            {
                Display_Call_Swap();
                g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_NULL;
            }

            break;
        }

        default:
        {       // save state
            CallParams->State          = State->calls[i].state;
            g_MMI_Call_Mng.CallProcess = UI_CALL_PROCESS_NULL;
            break;
        }
        } /* switch */
    }
#endif

#if USE_LV_BLUETOOTH
        if(bt_get_headset_connect() && !appbt_get_sco_status())
        {
            if(g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->IsECall)
            {
                Call_Spk_Ctrl(FALSE);
            }
        }
#endif

    for(UINT8 i = 0; i < State->count; i++) {
        Hal_Mem_Free(State->calls[i].number);
        Hal_Mem_Free(State->calls[i].name);
    }

    Hal_Mem_Free(State->calls);
    Hal_Mem_Free(State);
    Call_Print_Call_Info(__FUNCTION__);
}         /* MMI_Modem_Call_Response_State_Change */

/**
 * Indicates whether remote state is hold
 *
 * param SimId:  MMI_MODEM_SIM_ID
 * param Index:  Connection index
 * param IsHold: ture for hold, and false for unhold
 * return  void
 */
VOID Phone_Modem_Call_Response_Remote_Hold(MMI_MODEM_SIM_ID SimId, INT32 Index, BOOL IsHold)
{
    if (TRUE == IsHold)
    {
        Display_Call_Hold();
    }
    else
    {
        Display_Call_Unhold();
    }
    Call_Print_Call_Info(__FUNCTION__);
}

#if USE_LV_INTERPHONE_TEST == 0
/**
 * Indicates a result of checking ATD command
 * param isOk:  UINT8
 * return  void
 */
VOID Phone_Modem_Call_Response_Dial(UINT8 isOk)
{
    UI_Call_Params_t *CallParams;
    NV_Call_Log_Data_t *CallLogData;
    CALL_LOG_TYPE CallLogType = CALL_LOG_TYPE_NONE;

    if(isOk)
    { // CME ERROR
        CallParams = g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex];

        // delete this call from g_Calls
        if (NULL != CallParams)
        {
            // record call log
            CallLogType = CALL_LOG_TYPE_DIALLED;
            CallLogData = (NV_Call_Log_Data_t *)Hal_Mem_Alloc(sizeof(NV_Call_Log_Data_t));
            Hal_Mem_Set(CallLogData, 0, sizeof(NV_Call_Log_Data_t));
            CallLogData->Type = CallLogType;
            if (NULL != CallParams->Name)
            {
                Hal_Mem_Copy(CallLogData->Name, CallParams->Name, strlen(CallParams->Name));
            }
            Hal_Mem_Copy(CallLogData->Number, CallParams->Number, strlen(CallParams->Number));
            CallLogData->SimId     = CallParams->SimId;
            CallLogData->Duration  = CallParams->Duration;
            CallLogData->Timestamp = UI_Get_Timestamp_In_Second();
            CallLog_Call_Add_Log(CallLogData);

            Hal_Set_Voice_Call_Status(VOICE_CALL_END);
            Display_Call_End();
            Audio_Player_Audio_Contine();
            Call_Clear_Call_Paras(g_MMI_Call_Mng.ActiveIndex);
            Call_Duration_Stop();      // stop duration timer and reset variable Duration.
            g_MMI_Call_Mng.IsConnect = FALSE;
            Framework_Call_Calling_Or_Incoming_Ind(FALSE, FALSE);
        }
        else
        {
            UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "Call AT check should not received\n");
            return;
        }
    } else {  // OK
        // nothing
    }
    Call_Print_Call_Info(__FUNCTION__);
}
#endif

/**
 * Voice call request from framework
 * param Number: char*
 * return void
 */
VOID Call_Framework_Voice_Call_Req(INT8 *Number)
{
    If_Contacts_Contact_Para_t ContactPara;

    if(TRUE == Call_Setting_Is_Call_Present())
    {
        printf("%s: already in a call\n", __FUNCTION__);
        Hal_Mem_Free(Number);
        return;
    }

    Nav_Home(ACT_ID_ANY);   //nav home first

    g_MMI_Call_Mng.ActiveIndex = Call_Get_Free_Line();

    Contacts_Get_Contact_Para_Req(Number, &ContactPara);
    if (0 < strlen(ContactPara.Name))
    {
        Call_Enter_Call_Paras(g_MMI_Call_Mng.ActiveIndex, ContactPara.Name, Number);
    }
    else
    {
        Call_Enter_Call_Paras(g_MMI_Call_Mng.ActiveIndex, NULL, Number);
    }

    Hal_Mem_Free(Number);

    Call_Start_Call();
} /* Call_Framework_Voice_Call_Req */

/**
 * call disconnect request from framework
 * param void
 * return void
 */
VOID Call_Framework_Disconnect_Req(VOID)
{
    printf("%s\n", __FUNCTION__);

    if (NULL != g_MMI_Call_Mng.Calls[0])
    {
        MMI_Modem_Call_Request_Hangup(g_MMI_Call_Mng.Calls[0]->SimId, g_MMI_Call_Mng.Calls[0]->Index);
    }
    if (NULL != g_MMI_Call_Mng.Calls[1])
    {
        MMI_Modem_Call_Request_Hangup(g_MMI_Call_Mng.Calls[1]->SimId, g_MMI_Call_Mng.Calls[1]->Index);
    }
}

/**
 * Voice call request from contact
 * param Number: char*
 * return void
 */
VOID Contacts_Call_Req(INT8 *Name, INT8 *Number)
{
    if(TRUE == Call_Setting_Is_Call_Present())
    {
        printf("%s: already in a call\n", __FUNCTION__);
        Hal_Mem_Free(Name);
        Hal_Mem_Free(Number);
        return;
    }

    Nav_Home(ACT_ID_ANY);   //nav home first

    g_MMI_Call_Mng.ActiveIndex = 0;             // MO call at 0 position
    Call_Enter_Call_Paras(g_MMI_Call_Mng.ActiveIndex, Name, Number);
    Hal_Mem_Free(Name);
    Hal_Mem_Free(Number);
    Call_Start_Call();
} /* Contacts_Call_Req */

/**
 * response of Contacts_Select_Contact_Req(IF_CONTACTS_CALL_SEL_ONE_CONTACT);
 * param Name: char*
 * param Number: char*
 * return void
 */
VOID Contacts_Call_Select_Contact_Cnf(INT8 *Name, INT8 *Number)
{
    // not use currently
    UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_3, "%s\n", __FUNCTION__);
}

BOOL Call_Setting_Is_Call_Present(VOID)
{
    BOOL ret = FALSE;

    if(0 != g_MMI_Call_Mng.CallsBitMap)
    {
        ret = TRUE;
    }

    return ret;
}

UINT8 Call_Setting_Get_Speaker_Volume(VOID)
{
    UINT8 SpeakerVol;

    if (HAL_CALL_SPK_ON == g_MMI_Call_Mng.CallSpkStatus)
    {
        UI_NV_Read_Req(NV_SECTION_UI_CALL, CALL_NV_SPEAKER_OFFSET, 1, &SpeakerVol);
    }
    else
    {
        UI_NV_Read_Req(NV_SECTION_UI_CALL, CALL_NV_HANDSET_OFFSET, 1, &SpeakerVol);
    }

    return SpeakerVol;
}

#if USE_LV_BLUETOOTH
#include "../contact/contact_global.h"
#include "../calllog/call_log_global.h"
INT8 last_volume = -1;

VOID phone_bt_hfp_ata_message_handle(VOID)
{
    Hal_Set_Voice_Call_Status(VOICE_CALL_START);
    MMI_Modem_Call_Request_Answer(g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->SimId);
    Call_Stop_Ring();
    Nav_Back(ACT_ID_ANY);               // pop incoming ui
    Display_Call_Main();
}

VOID phone_bt_hfp_atchup_message_handle(VOID)
{
    Call_Stop_Ring();
    Call_Proc_End();
}

VOID phone_bt_hfp_dial_message_handle(VOID)
{
    INT8 * Number = NULL;
    if(0 == g_Call_Log_Mng.DialledCalls)
    {
        //no call history, so call index 0(manager) in contact
        Contacts_List_t *Contact = Contact = _lv_ll_get_head(&g_ContactsMng.ContactsList);
        if(NULL == Contact)
        {  //no contact
            printf("%s: no contact, dail fail\n", __FUNCTION__);
        }
        else
        {
            printf("%s: dial first number in contact\n", __FUNCTION__);
            Number = (INT8 *)Hal_Mem_Alloc(CONTACTS_MAX_NUMBER_LENGTH);
            Hal_Mem_Copy(Number, Contact->ContactInfo->Number, CONTACTS_MAX_NUMBER_LENGTH);
            Call_Framework_Voice_Call_Req(Number);
        }
    }
    else
    {
        printf("%s: call first num in dial calllog\n", __FUNCTION__);
        Number = (INT8 *)Hal_Mem_Alloc(NV_CONTACTS_MAX_NUMBER_LEN * sizeof(INT8));
        Hal_Mem_Copy(Number, g_Call_Log_Mng.CurrCallLog->Data.Number, NV_CONTACTS_MAX_NUMBER_LEN * sizeof(INT8));
        Call_Framework_Voice_Call_Req(Number);
    }
}

VOID phone_bt_hfp_atchld_message_handle(VOID)
{
    printf("VOID function %s", __FUNCTION__);
}

VOID phone_bt_hfp_recognition_message_handle(VOID * msg)
{
    printf("VOID function %s", __FUNCTION__);
}

VOID phone_bt_hfp_speaker_volume_message_handle(VOID * msg)
{
    lv_obj_t * bt_volume_slider;
    INT32 current_volume = ((mmi_msg_bt_hfp_value_response_t *)msg)->value;

    printf("%s volume is %d\n", __FUNCTION__, current_volume);

    if((last_volume == -1) || (last_volume == current_volume)) {
        last_volume = current_volume;
        return;
    }

    last_volume = current_volume;

    // do not display slider outside phone voip and player APP.
    if(Nav_Get_Top() != ACT_ID_CALL_CALLING && Nav_Get_Top() != ACT_ID_CALL_MAIN) return;

    bt_volume_slider = ((UI_Normal_NoTitle_Labels_Bar_Desc_t *)(g_MMI_Call_Mng.CurrentDesc))->Bar.Bar;
    lv_obj_set_hidden(bt_volume_slider, FALSE);
    lv_slider_set_range(bt_volume_slider, 0, HAL_BT_VOLUME_MAX);
    lv_slider_set_value(bt_volume_slider, current_volume, LV_ANIM_OFF);
    appbt_hfp_set_speaker_gain(current_volume);
}

VOID phone_bt_hfp_microphone_gain_message_handle(VOID * msg)
{
    printf("VOID function %s", __FUNCTION__);
}

VOID phone_bt_hfp_connected_message_handle(VOID)
{
    if((MMI_MODEM_CALL_STATE_ALERTING == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State) ||
       (MMI_MODEM_CALL_STATE_ACTIVE == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State)) {
        last_volume = -1;
        Hal_Set_BT_Audio_Path((HAL_SPEAKER_GAIN)Call_Setting_Get_Speaker_Volume());
    }
}
VOID phone_bt_hfp_disconnect_message_handle(VOID)
{
    if((MMI_MODEM_CALL_STATE_ALERTING == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State) ||
        (MMI_MODEM_CALL_STATE_ACTIVE == g_MMI_Call_Mng.Calls[g_MMI_Call_Mng.ActiveIndex]->State)) {
        Hal_Call_Speaker(HAL_CALL_SPK_ON, (HAL_SPEAKER_GAIN)Call_Setting_Get_Speaker_Volume());
    }
}
#endif
